package cn.changein.framework.config.Interceptor;

import cn.changein.framework.base.auth.jwt.JwtTokenUtil;
import cn.changein.framework.kernel.model.exception.enumeration.CoreExceptionEnum;
import cn.changein.framework.kernel.model.response.ErrorResponseData;
import cn.changein.framework.kernel.model.response.ResponseData;
import cn.changein.framework.util.ThreadContextHolder;
import com.alibaba.fastjson.JSONObject;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.util.Date;

/**
 * <p> TODO(jwt token 拦截器) </p>
 *

 * @version V1.0
 * @Title: JwtTokenInterceptor
 * @Package cn.changein.framework.config.Interceptor
 * @date 2021/1/23 17:08
 * @Copyright: companyName
 */
@Component
@Slf4j
public class JwtTokenInterceptor extends HandlerInterceptorAdapter {


    public JwtTokenInterceptor() {
        super();
    }

    /**
     * @Description: 拦截每个方法
     * @Date:2021/1/23 17:42
     * @Param: [request, response, handler]

     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String test = request.getHeader("is_test");
        if (StringUtils.equals(test, "is_test")) return true; //跳过测试
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            Method method = handlerMethod.getMethod();
            //请求方法,包含注解,需要拦截
            if (!method.isAnnotationPresent(LoginToken.class)) return true;
        } else {
            return true;
        }

        /****************需要 Token**********************/
        //Authorization: Bearer Token
        String authHeader = request.getHeader("Authorization"); //权限
        if (StringUtils.isBlank(authHeader)) {
            this.responseMessage(response, CoreExceptionEnum.TOKEN_NOT_EXIST.getCode(), CoreExceptionEnum.TOKEN_NOT_EXIST.getMessage());
            return false;
        }
        String token = authHeader.substring(7);
        if (StringUtils.isBlank(token)) {
            this.responseMessage(response, CoreExceptionEnum.TOKEN_NOT_EXIST.getCode(), CoreExceptionEnum.TOKEN_NOT_EXIST.getMessage());
            return false;
        }
        String loginId = request.getHeader("loginId"); //memberId
        if (StringUtils.isBlank(loginId)) {
            this.responseMessage(response, CoreExceptionEnum.MEMBER_NOT_LOGIN.getCode(), CoreExceptionEnum.MEMBER_NOT_LOGIN.getMessage());
            return false;
        }
        try {
            Claims claimFromToken = JwtTokenUtil.getClaimFromToken(token);
            if (null == claimFromToken) {
                this.responseMessage(response, CoreExceptionEnum.TOKEN_AUTHENTICATION_FAILED.getCode(), CoreExceptionEnum.TOKEN_AUTHENTICATION_FAILED.getMessage());
                return false;
            }
            String memberId = claimFromToken.getSubject();//memberId
            Date expiration = claimFromToken.getExpiration();
            if (null == expiration || expiration.compareTo(new Date()) < 0) {
                this.responseMessage(response, CoreExceptionEnum.TOKEN_AUTHENTICATION_EXPIRED.getCode(), CoreExceptionEnum.TOKEN_AUTHENTICATION_EXPIRED.getMessage());
                return false;
            }
            if (!StringUtils.equals(memberId, loginId)) { //
                this.responseMessage(response, CoreExceptionEnum.TOKEN_AUTHENTICATION_FAILED.getCode(), CoreExceptionEnum.TOKEN_AUTHENTICATION_FAILED.getMessage());
                return false;
            }
            ThreadContextHolder.setUserId(Long.valueOf(memberId));
            //进行解密
            log.info("解密成功 loginId={}", memberId);
        } catch (Exception e) {
            log.error("error={}", e.getMessage());
            this.responseMessage(response, CoreExceptionEnum.TOKEN_AUTHENTICATION_FAILED.getCode(), CoreExceptionEnum.TOKEN_AUTHENTICATION_FAILED.getMessage());
            return false;
        }
        return super.preHandle(request, response, handler);
    }


    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        String loginId = request.getHeader("loginId"); //memberId
        if (StringUtils.isNotBlank(loginId)) {
            ThreadContextHolder.remove();
        }
        super.postHandle(request, response, handler, modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        super.afterCompletion(request, response, handler, ex);
    }

    @Override
    public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        super.afterConcurrentHandlingStarted(request, response, handler);
    }

    private void responseMessage(HttpServletResponse response, Integer code, String message) {
        ErrorResponseData error = ResponseData.error(code, message);
        response.setContentType("application/json; charset=utf-8");
        PrintWriter out = null;
        try {
            out = response.getWriter();
            String json = JSONObject.toJSONString(error);
            out.print(json);
            out.flush();
        } catch (Exception e) {
            log.error("e={}", e.getMessage());
        } finally {
            if (null != out) {
                out.close();
            }
        }
    }
}
